﻿//MarketDataGenerator.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Algo.Testing
{
	using System;

	using Ecng.Common;

	using StockSharp.BusinessEntities;

	/// <summary>
	/// Генератор случайным образом маркет-данных.
	/// </summary>
	/// <typeparam name="TData">Тип маркер-данных.</typeparam>
	public abstract class MarketDataGenerator<TData> : Cloneable<MarketDataGenerator<TData>>
	{
		/// <summary>
		/// Инициализировать <see cref="MarketDataGenerator{TData}"/>.
		/// </summary>
		/// <param name="security">Инструмент, для которого необходимо генерировать данные.</param>
		protected MarketDataGenerator(Security security)
		{
			Security = security.CheckMinStepSize();

			MaxVolume = 20;
			MinVolume = 1;
			MaxPriceStepCount = 10;
		}

		/// <summary>
		/// Инициализировать состояние генератора.
		/// </summary>
		public virtual void Init()
		{
			LastGenerationTime = DateTime.MinValue;

			Volumes = new RandomArray<int>(MinVolume, MaxVolume, 1000000);
			Steps = new RandomArray<int>(1, MaxPriceStepCount, 1000000);
		}

		/// <summary>
		/// Инструмент, для которого необходимо генерировать данные.
		/// </summary>
		public Security Security { get; private set; }

		/// <summary>
		/// Время последней генерации данных.
		/// </summary>
		public DateTime LastGenerationTime { get; private set; }

		/// <summary>
		/// Интервал генерации данных.
		/// </summary>
		public TimeSpan Interval { get; set; }

		private int _maxVolume;

		/// <summary>
		/// Максимальный объем. Объем будет выбран случайно от <see cref="MinVolume"/> до <see cref="MaxVolume"/>.
		/// </summary>
		/// <remarks>
		/// Значение по умолчанию равно 20.
		/// </remarks>
		public int MaxVolume
		{
			get { return _maxVolume; }
			set
			{
				if (value < 1)
					throw new ArgumentOutOfRangeException("value", value, "Максимальный объем не может быть меньше одного.");

				_maxVolume = value;
			}
		}

		private int _minVolume;

		/// <summary>
		/// Максимальный объем. Объем будет выбран случайно от <see cref="MinVolume"/> до <see cref="MaxVolume"/>.
		/// </summary>
		/// <remarks>
		/// Значение по умолчанию равно 1.
		/// </remarks>
		public int MinVolume
		{
			get { return _minVolume; }
			set
			{
				if (value < 1)
					throw new ArgumentOutOfRangeException("value", value, "Минимальный объем не может быть меньше одного.");

				_minVolume = value;
			}
		}

		private int _maxPriceStepCount;

		/// <summary>
		/// Максимальное количество шагов цены <see cref="BusinessEntities.Security.MinStepSize"/>, которое будет возвращатся через массив <see cref="Steps"/>.
		/// </summary>
		/// <remarks>
		/// Значение по умолчанию равно 10.
		/// </remarks>
		public int MaxPriceStepCount
		{
			get { return _maxPriceStepCount; }
			set
			{
				if (value < 2)
					throw new ArgumentOutOfRangeException("value", value, "Максимальное количество шагов не может быть меньше двух.");

				_maxPriceStepCount = value;
			}
		}

		/// <summary>
		/// Сгенерировать маркет-данные.
		/// </summary>
		/// <param name="data">Маркет-данные.</param>
		/// <param name="time">Текущее время.</param>
		public virtual void Generate(TData data, DateTime time)
		{
			LastGenerationTime = time;
		}

		/// <summary>
		/// Требуется ли генерация новых данных.
		/// </summary>
		/// <param name="time">Текущее время.</param>
		/// <returns>true если надо сгенерировать данные.</returns>
		public virtual bool IsTimeToGenerate(DateTime time)
		{
			return time >= LastGenerationTime + Interval;
		}

		private RandomArray<int> _volumes;

		/// <summary>
		/// Массив случайных объемов в диапазоне от <see cref="MinVolume"/> до <see cref="MaxVolume"/>.
		/// </summary>
		public RandomArray<int> Volumes
		{
			get
			{
				if (_volumes == null)
					throw new InvalidOperationException("Генератор не инициализирован.");

				return _volumes;
			}
			protected set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				_volumes = value;
			}
		}

		private RandomArray<int> _steps;

		/// <summary>
		/// Массив случайных количеств шагов цены в диапазоне от 1 до <see cref="MaxPriceStepCount"/>.
		/// </summary>
		public RandomArray<int> Steps
		{
			get
			{
				if (_steps == null)
					throw new InvalidOperationException("Генератор не инициализирован.");

				return _steps;
			}
			protected set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				_steps = value;
			}
		}
	}
}